package com.newlink.building.activities.main.dialer.fragments

import android.Manifest
import android.annotation.TargetApi
import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.transition.MaterialSharedAxis
import com.newlink.building.NL_App.Companion.coreContext
import com.newlink.building.NL_App.Companion.corePreferences
import com.newlink.building.R
import com.newlink.building.activities.main.Module_Phone_LinphoneMainActivity
import com.newlink.building.activities.main.dialer.adapter.Module_Phone_DialerHistoryAdapter
import com.newlink.building.activities.main.dialer.adapter.Module_Phone_DialerSearchAdapter
import com.newlink.building.activities.main.dialer.viewmodels.Module_Phone_DialerViewModel
import com.newlink.building.activities.main.fragments.Module_Phone_MasterFragment
import com.newlink.building.activities.main.history.data.Module_Phone_GroupedCallLogData
import com.newlink.building.activities.main.history.viewmodels.Module_Phone_CallLogsListViewModel
import com.newlink.building.activities.main.settings.viewmodels.Module_Phone_CallSettingsViewModel
import com.newlink.building.activities.main.viewmodels.Module_Phone_DialogViewModel
import com.newlink.building.activities.main.viewmodels.Module_Phone_SharedMainViewModel
import com.newlink.building.bean.Module_Phone_TitleBarBean
import com.newlink.building.compatibility.Module_Phone_Compatibility
import com.newlink.building.databinding.DialerFragmentBinding
import com.newlink.building.telecom.Module_Phone_TelecomHelper
import com.newlink.building.utils.Module_Phone_AppUtils
import com.newlink.building.utils.Module_Phone_DialogUtils
import com.newlink.building.utils.Module_Phone_PermissionHelper
import org.linphone.core.tools.Log
import org.linphone.mediastream.Version

/**
 * @author wangyang
 * @date 2022/11/15
 * @description 拨号页面
 */
class Module_Phone_DialerFragment : Module_Phone_MasterFragment<DialerFragmentBinding, Module_Phone_DialerHistoryAdapter>() {
    private lateinit var viewModel: Module_Phone_DialerViewModel
    private lateinit var sharedViewModel: Module_Phone_SharedMainViewModel
    private lateinit var callLogsListViewModel: Module_Phone_CallLogsListViewModel
    private lateinit var dialerHistoryAdapter: Module_Phone_DialerHistoryAdapter

    private var uploadLogsInitiatedByUs = false

    override fun getLayoutId(): Int = R.layout.dialer_fragment

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val callSettingsViewModel = ViewModelProvider(this)[Module_Phone_CallSettingsViewModel::class.java]
//        callSettingsViewModel.acceptEarlyMedia.value = true
//        corePreferences.acceptEarlyMedia = true

        binding.lifecycleOwner = viewLifecycleOwner
        binding.listTopBarViewModel = listSelectionViewModel

        viewModel = ViewModelProvider(this)[Module_Phone_DialerViewModel::class.java]
        binding.viewModel = viewModel

        viewModel.mSipIconContentDescription.observe(viewLifecycleOwner) {
            val mTitleBarBean = Module_Phone_TitleBarBean()
            mTitleBarBean.isShowLeftImg.value = true
            mTitleBarBean.isShowLeftText.value = true
            mTitleBarBean.isShowCenterText.value = true
            mTitleBarBean.isShowRightImg.value = true

            val identityAddress = coreContext.core.defaultAccount?.params?.identityAddress
            if (identityAddress?.displayName.isNullOrEmpty()) {
                mTitleBarBean.leftContent.value =
                    "${identityAddress?.username}(${viewModel.mSipIconContentDescription.value})"
            } else {
                mTitleBarBean.leftContent.value =
                    "${identityAddress?.displayName}(${viewModel.mSipIconContentDescription.value})"
            }
            mTitleBarBean.centerContent.value = getString(R.string.title_dial)
            binding.titleBarBean = mTitleBarBean
        }
        viewModel.onDialerHistoryTabClick.handleClick(0)
        dialerHistoryAdapter = context?.let {
            Module_Phone_DialerHistoryAdapter(listSelectionViewModel, viewLifecycleOwner)
        }!!
        _adapter = dialerHistoryAdapter
        binding.rvHistory.setHasFixedSize(true)
        binding.rvHistory.adapter = dialerHistoryAdapter
        val layoutManager = LinearLayoutManager(activity)
        binding.rvHistory.layoutManager = layoutManager
        binding.rvHistory.setOnTouchListener { v, event ->
            viewModel.mShowDialerPlate.value = false
            false
        }

        callLogsListViewModel = ViewModelProvider(this)[Module_Phone_CallLogsListViewModel::class.java]
        callLogsListViewModel.displayCallLogs.observe(viewLifecycleOwner) {
            viewModel.mCallLogsListData.value = it
            if (viewModel.mCallLogsState.value == 0) {
                refreshCallLogs(0)
            }
        }
        callLogsListViewModel.displayOutgoingCallLogs.observe(viewLifecycleOwner) {
            viewModel.mOutgoingCallLogsListData.value = it
            if (viewModel.mCallLogsState.value == 1) {
                refreshCallLogs(1)
            }
        }
        callLogsListViewModel.displayMissedCallLogs.observe(viewLifecycleOwner) {
            viewModel.mMissedCallLogsListData.value = it
            if (viewModel.mCallLogsState.value == 2) {
                refreshCallLogs(2)
            }
        }

        viewModel.mCallLogsState.observe(viewLifecycleOwner) {
            refreshCallLogs(it)
        }

        binding.titleBar?.setTitleBarRightClickListener {
            listSelectionViewModel.isEditionEnabled.value =
                !listSelectionViewModel.isEditionEnabled.value!!
            viewModel.mShowDialerPlate.value = false
        }

        var dialerSearchAdapter =
            context?.let {
                Module_Phone_DialerSearchAdapter(
                    it,
                    viewModel.mCallLogsSearchListData.value
                        ?: ArrayList<Module_Phone_GroupedCallLogData>()
                )
            }
        binding.rvSearch.adapter = dialerSearchAdapter
        binding.rvSearch.setOnTouchListener { v, event ->
            viewModel.mShowDialerPlate.value = false
            false
        }
        callLogsListViewModel.displayCallLogsSortByName.observe(viewLifecycleOwner) {
            viewModel.mCallLogsSearchListData.value = it
            viewModel.mCallLogsSearchListData.value?.let { it1 ->
                dialerSearchAdapter?.refreshData(
                    it1
                )
            }
        }

        binding.etCallPhone?.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            }

            override fun afterTextChanged(s: Editable?) {
                viewModel.enteredUri.value = s.toString()
                var displayName = viewModel.enteredUri.value
                displayName = displayName?.replace("*", ".", true)
                callLogsListViewModel.sortCallLogsByName(displayName)
            }
        })

        viewModel.mDialerEditText.value = binding.etCallPhone
        binding.etCallPhone?.setOnTouchListener { v, event ->
            viewModel.onFocusUriChanged(binding.etCallPhone!!)
            false
        }

        binding.dialerPlate?.ll?.setOnClickListener { }
        binding.llDialerPlateHidden?.setOnClickListener {
            viewModel.mShowDialerPlate.value = false
        }
        binding.llDialerPlateShow?.setOnClickListener {
            viewModel.mShowDialerPlate.value = true
        }

        sharedViewModel = requireActivity().run {
            ViewModelProvider(this)[Module_Phone_SharedMainViewModel::class.java]
        }

        sharedViewModel.refreshDataCommandEvent.observe(
            viewLifecycleOwner
        ) {
            it.consume {
                callLogsListViewModel.deleteAllCallLog()
            }
        }

        useMaterialSharedAxisXForwardAnimation = false
        sharedViewModel.updateDialerAnimationsBasedOnDestination.observe(
            viewLifecycleOwner
        ) {
            it.consume { id ->
                val forward = when (id) {
//                    R.id.masterChatRoomsFragment -> false
                    else -> true
                }
                if (corePreferences.enableAnimations) {
                    val portraitOrientation =
                        resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE
                    val axis =
                        if (portraitOrientation) MaterialSharedAxis.X else MaterialSharedAxis.Y
                    enterTransition = MaterialSharedAxis(axis, forward)
                    reenterTransition = MaterialSharedAxis(axis, forward)
                    returnTransition = MaterialSharedAxis(axis, !forward)
                    exitTransition = MaterialSharedAxis(axis, !forward)
                }
            }
        }

//        binding.setNewContactClickListener {
//            sharedViewModel.updateDialerAnimationsBasedOnDestination.value =
//                Event(R.id.masterContactsFragment)
//            sharedViewModel.updateContactsAnimationsBasedOnDestination.value =
//                Event(R.id.dialerFragment)
//            navigateToContacts(viewModel.enteredUri.value)
//        }
//
//        binding.setTransferCallClickListener {
//            if (viewModel.transferCall()) {
//                // Transfer has been consumed, otherwise it might have been a "bis" use
//                sharedViewModel.pendingCallTransfer = false
//                viewModel.transferVisibility.value = false
//            }
//        }

        viewModel.enteredUri.observe(
            viewLifecycleOwner
        ) {
            if (it == corePreferences.debugPopupCode) {
                displayDebugPopup()
                viewModel.enteredUri.value = ""
            }
        }

        viewModel.uploadFinishedEvent.observe(
            viewLifecycleOwner
        ) {
            it.consume { url ->
                // To prevent being trigger when using the Send Logs button in About page
                if (uploadLogsInitiatedByUs) {
                    val clipboard =
                        requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
                    val clip = ClipData.newPlainText("Logs url", url)
                    clipboard.setPrimaryClip(clip)

                    val activity = requireActivity() as Module_Phone_LinphoneMainActivity
                    activity.showSnackBar(R.string.logs_url_copied_to_clipboard)

                    Module_Phone_AppUtils.shareUploadedLogsUrl(activity, url)
                }
            }
        }

        viewModel.updateAvailableEvent.observe(
            viewLifecycleOwner
        ) {
            it.consume { url ->
                displayNewVersionAvailableDialog(url)
            }
        }

        if (corePreferences.firstStart) {
            Log.w("[Dialer] First start detected, wait for assistant to be finished to check for update & request permissions")
            return
        }

        if (arguments?.containsKey("Transfer") == true) {
            sharedViewModel.pendingCallTransfer = arguments?.getBoolean("Transfer") ?: false
            Log.i("[Dialer] Is pending call transfer: ${sharedViewModel.pendingCallTransfer}")
        }

        if (arguments?.containsKey("URI") == true) {
            val address = arguments?.getString("URI") ?: ""
            Log.i("[Dialer] Found URI to call: $address")
            val skipAutoCall = arguments?.getBoolean("SkipAutoCallStart") ?: false

            if (corePreferences.callRightAway && !skipAutoCall) {
                Log.i("[Dialer] Call right away setting is enabled, start the call to $address")
                viewModel.directCall(address)
            } else {
                sharedViewModel.dialerUri = address
            }
        }
        arguments?.clear()

        Log.i("[Dialer] Pending call transfer mode = ${sharedViewModel.pendingCallTransfer}")
        viewModel.transferVisibility.value = sharedViewModel.pendingCallTransfer

//        checkForUpdate()

        if (Version.sdkAboveOrEqual(Version.API23_MARSHMALLOW_60)) {
//            checkPermissions()
        }
    }

    override fun onPause() {
        sharedViewModel.dialerUri = viewModel.enteredUri.value ?: ""
        super.onPause()
    }

    override fun onResume() {
        super.onResume()

//        if (resources.getBoolean(R.bool.isTablet)) {
//            coreContext.core.nativePreviewWindowId = binding.videoPreviewWindow
//        }
        sharedViewModel.hideNavigationBar.value =
            false

        viewModel.updateShowVideoPreview()
        viewModel.autoInitiateVideoCalls.value =
            coreContext.core.videoActivationPolicy.automaticallyInitiate
        uploadLogsInitiatedByUs = false

        viewModel.enteredUri.value = sharedViewModel.dialerUri

        viewModel.mSipLine.value =
            coreContext.core.defaultAccount?.params?.identityAddress?.username
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if (requestCode == 0) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.i("[Dialer] READ_PHONE_STATE permission has been granted")
                coreContext.initPhoneStateListener()
            }
            checkTelecomManagerPermissions()
        } else if (requestCode == 1) {
            var allGranted = true
            for (result in grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    allGranted = false
                }
            }
            if (allGranted) {
                Log.i("[Dialer] Telecom Manager permission have been granted")
                enableTelecomManager()
            } else {
                Log.w("[Dialer] Telecom Manager permission have been denied (at least one of them)")
            }
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }

    @TargetApi(Version.API23_MARSHMALLOW_60)
    private fun checkPermissions() {
        checkReadPhoneStatePermission()
        if (Version.sdkAboveOrEqual(Version.API26_O_80) && Module_Phone_PermissionHelper.get()
                .hasReadPhoneStatePermission()
        ) {
            // Don't check the following the previous permission is being asked
            checkTelecomManagerPermissions()
        }
    }

    @TargetApi(Version.API23_MARSHMALLOW_60)
    private fun checkReadPhoneStatePermission() {
        if (!Module_Phone_PermissionHelper.get().hasReadPhoneStatePermission()) {
            Log.i("[Dialer] Asking for READ_PHONE_STATE permission")
            requestPermissions(arrayOf(Manifest.permission.READ_PHONE_STATE), 0)
        }
    }

    @TargetApi(Version.API26_O_80)
    private fun checkTelecomManagerPermissions() {
        if (!corePreferences.useTelecomManager) {
            Log.i("[Dialer] Telecom Manager feature is disabled")
            if (corePreferences.manuallyDisabledTelecomManager) {
                Log.w("[Dialer] User has manually disabled Telecom Manager feature")
            } else {
                if (Module_Phone_Compatibility.hasTelecomManagerPermissions(requireContext())) {
                    enableTelecomManager()
                } else {
                    Log.i("[Dialer] Asking for Telecom Manager permissions")
                    Module_Phone_Compatibility.requestTelecomManagerPermissions(requireActivity(), 1)
                }
            }
        } else {
            Log.i("[Dialer] Telecom Manager feature is already enabled")
        }
    }

    @TargetApi(Version.API26_O_80)
    private fun enableTelecomManager() {
        Log.i("[Dialer] Telecom Manager permissions granted")
        if (!Module_Phone_TelecomHelper.exists()) {
            Log.i("[Dialer] Creating Telecom Helper")
            if (requireContext().packageManager.hasSystemFeature(PackageManager.FEATURE_CONNECTION_SERVICE)) {
                Module_Phone_TelecomHelper.create(requireContext())
            } else {
                Log.e("[Dialer] Telecom Helper can't be created, device doesn't support connection service!")
                return
            }
        } else {
            Log.e("[Dialer] Telecom Manager was already created ?!")
        }
        corePreferences.useTelecomManager = true
    }

    private fun displayDebugPopup() {
        val alertDialog = MaterialAlertDialogBuilder(requireContext())
        alertDialog.setTitle(getString(R.string.debug_popup_title))

        val items = if (corePreferences.debugLogs) {
            resources.getStringArray(R.array.popup_send_log)
        } else {
            resources.getStringArray(R.array.popup_enable_log)
        }

        alertDialog.setItems(items) { _, which ->
            when (items[which]) {
                getString(R.string.debug_popup_disable_logs) -> {
                    corePreferences.debugLogs = false
                }

                getString(R.string.debug_popup_enable_logs) -> {
                    corePreferences.debugLogs = true
                }

                getString(R.string.debug_popup_send_logs) -> {
                    uploadLogsInitiatedByUs = true
                    viewModel.uploadLogs()
                }

                getString(R.string.debug_popup_show_config_file) -> {
//                    navigateToConfigFileViewer()
                }
            }
        }

        alertDialog.show()
    }

    private fun checkForUpdate() {
        val lastTimestamp: Int = corePreferences.lastUpdateAvailableCheckTimestamp
        val currentTimeStamp = System.currentTimeMillis().toInt()
        val interval: Int = corePreferences.checkUpdateAvailableInterval
        if (lastTimestamp == 0 || currentTimeStamp - lastTimestamp >= interval) {
//            val currentVersion = BuildConfig.VERSION_NAME
            val currentVersion = requireActivity().getString(R.string.linphone_sdk_version)
            Log.i("[Dialer] Checking for update using current version [$currentVersion]")
            coreContext.core.checkForUpdate(currentVersion)
            corePreferences.lastUpdateAvailableCheckTimestamp = currentTimeStamp
        }
    }

    private fun displayNewVersionAvailableDialog(url: String) {
        val viewModel = Module_Phone_DialogViewModel(getString(R.string.dialog_update_available))
        val dialog: Dialog = Module_Phone_DialogUtils.getDialog(requireContext(), viewModel)

        viewModel.showCancelButton {
            dialog.dismiss()
        }

        viewModel.showOkButton(
            {
                try {
                    val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
                    startActivity(browserIntent)
                } catch (ise: IllegalStateException) {
                    Log.e("[Dialer] Can't start ACTION_VIEW intent, IllegalStateException: $ise")
                } finally {
                    dialog.dismiss()
                }
            },
            getString(R.string.dialog_ok)
        )

        dialog.show()
    }

    private fun refreshCallLogs(callLogsState: Int) {
        if (callLogsState == 0) {
            if (viewModel.mCallLogsListData.value.isNullOrEmpty()) {
                binding.tvNoCallLogs.visibility = View.VISIBLE
                binding.rvHistory.visibility = View.GONE
            } else {
                binding.tvNoCallLogs.visibility = View.GONE
                binding.rvHistory.visibility = View.VISIBLE
                viewModel.mCallLogsListData.value?.let { it1 ->
                    dialerHistoryAdapter?.submitList(it1)
                }
            }
        } else if (callLogsState == 1) {
            if (viewModel.mOutgoingCallLogsListData.value.isNullOrEmpty()) {
                binding.tvNoCallLogs.visibility = View.VISIBLE
                binding.rvHistory.visibility = View.GONE
            } else {
                binding.tvNoCallLogs.visibility = View.GONE
                binding.rvHistory.visibility = View.VISIBLE
                viewModel.mOutgoingCallLogsListData.value?.let { it1 ->
                    dialerHistoryAdapter?.submitList(it1)
                }
            }
        } else if (callLogsState == 2) {
            if (viewModel.mMissedCallLogsListData.value.isNullOrEmpty()) {
                binding.tvNoCallLogs.visibility = View.VISIBLE
                binding.rvHistory.visibility = View.GONE
            } else {
                binding.tvNoCallLogs.visibility = View.GONE
                binding.rvHistory.visibility = View.VISIBLE
                viewModel.mMissedCallLogsListData.value?.let { it1 ->
                    dialerHistoryAdapter?.submitList(it1)
                }
            }
        }

        Handler().postDelayed(
            {
                binding.rvHistory.scrollToPosition(0)
            },
            50
        )
    }

    /**
     * 删除通话记录
     */
    private fun deleteCallLogs(indexesOfItemToDelete: ArrayList<Int>) {
        listSelectionViewModel.isEditionEnabled.value =
            !listSelectionViewModel.isEditionEnabled.value!!
        viewModel.mShowDialerPlate.value = false

        val deleteList = ArrayList<Module_Phone_GroupedCallLogData>()
        for (index in indexesOfItemToDelete) {
            val callLog = adapter.currentList[index]
            if (callLog != null) {
                deleteList.add(callLog)
            }
            callLogsListViewModel.deleteCallLogGroups(deleteList)
        }

        if (viewModel.mCallLogsState.value == 0) {
            viewModel.mCallLogsListData.value?.let { it1 ->
                dialerHistoryAdapter?.submitList(it1)
            }
        } else if (viewModel.mCallLogsState.value == 1) {
            viewModel.mOutgoingCallLogsListData.value?.let { it1 ->
                dialerHistoryAdapter?.submitList(it1)
            }
        } else if (viewModel.mCallLogsState.value == 2) {
            viewModel.mMissedCallLogsListData.value?.let { it1 ->
                dialerHistoryAdapter?.submitList(it1)
            }
        }
    }

    override fun deleteItems(indexesOfItemToDelete: ArrayList<Int>) {
        deleteCallLogs(indexesOfItemToDelete)
    }
}
